package net.tycmc.cty.ctyms.timejob.iems.service;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import net.tycmc.bulb.common.util.StringUtil;
import net.tycmc.cty.ctyms.timejob.common.DateControl;
import net.tycmc.cty.ctyms.timejob.common.DynamicReadConfig;
import net.tycmc.cty.ctyms.timejob.common.EquipVersionCommon;
import net.tycmc.cty.ctyms.timejob.function.mail.SendMail;
import net.tycmc.cty.ctyms.timejob.iems.dao.FileToFTPDAO;

import org.apache.commons.configuration.ConfigurationException;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPReply;

import com.tycmc.functions.util.MapGetter;

public class FileToFTPService {
	private FileToFTPDAO fileToFTPDAO;
	private ParamConSaveAsFileService paramFileService;
	private String FtpAddress;
	private String FtpPort;
	private String FtpUser;
	private String FtpPass;
	private String CsvPath;
	private String CsvRootPath;

	public void fileToFTP() {
		String isHistory = null;
		String Times = null;
		String Vcls = null;
		try {
			FtpAddress = DynamicReadConfig.getConfigProperty("config.properties", "FtpAddress");
			FtpPort = DynamicReadConfig.getConfigProperty("config.properties","FtpPort");
			FtpUser = DynamicReadConfig.getConfigProperty("config.properties","FtpUser");
			FtpPass = DynamicReadConfig.getConfigProperty("config.properties","FtpPass");
			isHistory = DynamicReadConfig.getConfigProperty("config.properties","isHistory");
			Times = DynamicReadConfig.getConfigProperty("config.properties","Times");
			Vcls = DynamicReadConfig.getConfigProperty("config.properties","Vcls");
			CsvRootPath = fileToFTPDAO.getCsvPath().replace("\\", "/");
			String FileAddress = DynamicReadConfig.getConfigProperty("config.properties","FileAddress");
			if(StringUtil.isValid(FileAddress)){
				CsvRootPath = FileAddress+CsvRootPath.split(":")[1];
			}
			// 获取CSV文件夹路径,例如：E:\csv
			CsvPath = CsvRootPath + "/" + DateControl.getFormatDate(getNewDate(DateControl.getDateTime(1),-1),4);
		} catch (ConfigurationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		 
		if(StringUtil.isValid(isHistory) && isHistory.equals("0")){
			// 将当天日期文件夹下的文件依次上传
			tree(new File(CsvPath),"");

			Map<String,List<String>> datas = new HashMap<String,List<String>>();
			
			// 延迟数据处理并生成CSV文件
			bufferDataToCSVFile(datas);
			
			//将延迟数据上传至FTP服务器
			treeBufferData(datas);
		}else if(StringUtil.isValid(isHistory) && isHistory.equals("1")){
			//历史数据补传
			treeHis(Times,Vcls);
		}else{
			System.out.println(DateControl.getDateTime(0) + "：上传文件没有执行，也没有执行历史补传！" );
		}
	}
	//历史数据补传
	public void treeHis(String Times,String Vcls){
		if(StringUtil.isValid(Times)&&!StringUtil.isValid(Vcls)){
			String[] Time = Times.split(",");
			for (int j = 0; j < Time.length; j++) {
				File f = new File(CsvRootPath+"/"+Time[j]);
				// 判断传入对象是否为一个文件夹对象
				if (!f.isDirectory()) {
					System.out.println(DateControl.getDateTime(0) + "：历史数据文件夹路径不存在：" + CsvRootPath+"/"+Time[j]);
				} else {
					File[] t = f.listFiles();
					System.out.println(DateControl.getDateTime(0)+"["+Time[j]+"]该文件夹，共需要上传["+t.length+"]个历史文件！");
					String Message = DateControl.getDateTime(0)+"["+Time[j]+"]该文件夹，共需要上传["+t.length+"]个历史文件！<br /><br/>";
					int FailNum = 0;
					
					//建立FTP连接
					FTPClient ftp = getConnection(FtpAddress, Integer.parseInt(FtpPort), FtpUser, FtpPass, Time[j]);
					for (int i = 0; i < t.length; i++) {
						// 判断文件列表中的对象是否为文件夹对象，如果是则执行tree递归，直到把此文件夹中所有文件输出为止
						if (!t[i].isDirectory()) {
							boolean flag = upLoadFile(ftp,t[i].getName(), CsvRootPath+"/"+Time[j] + "/"+ t[i].getName(),0);
							if (!flag) {
								System.out.println(DateControl.getDateTime(0)+ "：历史数据补传文件上传失败：" + t[i].getName());
								Message += DateControl.getDateTime(0)+ "：历史数据补传文件上传失败：" + t[i].getName()+"<br /><br/>";
								FailNum++;
							}
						}
					}
					//关闭FTP连接
					disconnectFtp(ftp);
					
					//邮件发送上传失败文件名称
					if(FailNum>0){
						List<String> emailTo = emailTo();
						SendMail.getInstance().sendMail("IEMS FTP文件上传  "+DateControl.getFormatDate(DateControl.getDateTime(0), 3)+" 上传失败文件报告", Message, emailTo);	
					}
				}
			}
		}else if(StringUtil.isValid(Times)&&StringUtil.isValid(Vcls)){
			String[] Time = Times.split(",");
			String[] Vcl = Vcls.split(",");
			for (int j = 0; j < Time.length; j++) {
				File f = new File(CsvRootPath+"/"+Time[j]);
				// 判断传入对象是否为一个文件夹对象
				if (!f.isDirectory()) {
					System.out.println(DateControl.getDateTime(0) + "：历史数据文件夹路径不存在：" + CsvRootPath+"/"+Time[j]);
				} else {
					File[] t = f.listFiles();
					System.out.println(DateControl.getDateTime(0)+"["+Time[j]+"]该文件夹，共需要上传["+t.length+"]个历史文件！");
					String Message = DateControl.getDateTime(0)+"["+Time[j]+"]该文件夹，共需要上传["+t.length+"]个历史文件！<br /><br/>";
					int FailNum = 0;
					
					//建立FTP连接
					FTPClient ftp = getConnection(FtpAddress, Integer.parseInt(FtpPort), FtpUser, FtpPass, Time[j]);
					for (int i = 0; i < t.length; i++) {
						// 判断文件列表中的对象是否为文件夹对象，如果是则执行tree递归，直到把此文件夹中所有文件输出为止
						String fileName = t[i].getName();
						//判断是否在Vcls范围内
						for (int k = 0; k < Vcl.length; k++) {
							if(fileName.split("_")[0].equals(Vcl[k]) && !t[i].isDirectory() ){
								boolean flag = upLoadFile(ftp, fileName, CsvRootPath+"/"+Time[j] + "/"+ fileName,0);
								if (!flag) {
									System.out.println(DateControl.getDateTime(0)+ "：历史数据补传文件上传失败：" + fileName);
									Message += DateControl.getDateTime(0)+ "：历史数据补传文件上传失败：" + fileName+"<br /><br/>";
									FailNum++;
								}
							}
						}
					}
					//关闭FTP连接
					disconnectFtp(ftp);
					
					//邮件发送上传失败文件名称
					if(FailNum>0){
						List<String> emailTo = emailTo();
						SendMail.getInstance().sendMail("IEMS FTP文件上传  "+DateControl.getFormatDate(DateControl.getDateTime(0), 3)+" 上传失败文件报告", Message, emailTo);	
					}
				}
			}
		}else if(!StringUtil.isValid(Times)&&!StringUtil.isValid(Vcls)){
			tree(new File(CsvRootPath),"历史数据补传");
		}
	}
	
	// 延迟数据处理并生成CSV文件
	public void bufferDataToCSVFile(Map<String,List<String>> datas){
		String maxId = fileToFTPDAO.getMaxId();
		// 获取有延迟数据的时间集合
		List<Map<String, Object>> timeList = fileToFTPDAO.getTimes(maxId);
		String upMaxID="";
		for (int i = 0; i < timeList.size(); i++) {
			List<String> vcls = new ArrayList<String>();
			
			Map<String,Object> map = timeList.get(i);
			String MsgTime = MapGetter.getString(map, "Times");
			if(i==timeList.size()-1){
				upMaxID = MapGetter.getString(map, "MsgBF_ID");
			}
			String[] time = new String[]{MsgTime,getNewDate(MsgTime,1)};
			
			// CAN设备
			String canSoftVers = EquipVersionCommon.getSoftVerByAgrType("Vcl_J");
			List<Map<String, Object>> vcls403 = fileToFTPDAO.getVclsOfSoft(canSoftVers,maxId,MsgTime,"4");
			for (Map<String,Object> vcl : vcls403) {
				vcls.add(MapGetter.getString(vcl, "VehicleID")+"_"+DateControl.getFormatDate(MsgTime, 4)+"_can.csv");
			}
			paramFileService.saveFileOfParameters(CsvRootPath+"/", time, vcls403, "can");
			
			// PP设备
			String ppSoftVers = EquipVersionCommon.getSoftVerByAgrType("Vcl_PP");
			List<Map<String,Object>> vcls412 = fileToFTPDAO.getVclsOfSoft(ppSoftVers,maxId,MsgTime,"5");
			for (Map<String,Object> vcl : vcls412) {
				vcls.add(MapGetter.getString(vcl, "VehicleID")+"_"+DateControl.getFormatDate(MsgTime, 4)+"_uds.csv");
			}
			paramFileService.saveFileOfParameters(CsvRootPath+"/",time,vcls412,"uds");
			
			// JPP设备
			String jppSoftVers = EquipVersionCommon.getSoftVerByAgrType("Vcl_JPP");
			List<Map<String,Object>> vcls414 = fileToFTPDAO.getVclsOfSoft(jppSoftVers,maxId,MsgTime,"5,6");
			for (Map<String,Object> vcl : vcls414) {
				vcls.add(MapGetter.getString(vcl, "VehicleID")+"_"+DateControl.getFormatDate(MsgTime, 4)+"_uds.csv");
				vcls.add(MapGetter.getString(vcl, "VehicleID")+"_"+DateControl.getFormatDate(MsgTime, 4)+"_pgn.csv");
			}
			paramFileService.saveFileOfParameters(CsvRootPath+"/",time,vcls414,"uds");
			paramFileService.saveFileOfParameters(CsvRootPath+"/",time,vcls414,"pgn");
			
			//总设备集合
			datas.put(MsgTime, vcls);
		}
		//更新最大值
		if(StringUtil.isValid(upMaxID)){
			boolean flag = fileToFTPDAO.upMaxID(upMaxID);
			if(!flag){
				System.out.println(DateControl.getDateTime(0) + "：更新StatR_Type的类型为4（数据文件上传，缓存记录）------失败！");
			}
		}
	}

	//指定日期加减
	public String getNewDate(String date, int d) {
		SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
		Calendar ca = Calendar.getInstance();
		try {
			ca.setTime(formatter.parse(date));
		} catch (ParseException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		ca.add(Calendar.DATE, d);

		return formatter.format(ca.getTime());
	}

	public void tree(File f,String log) {
		// 判断传入对象是否为一个文件夹对象
		String Message = "";
		String SuccMsg = "";
		String FailMsg = "";
		if (!f.isDirectory()) {
			System.out.println(DateControl.getDateTime(0) + "："+log+"文件夹路径不存在：" + CsvPath);
			Message = DateControl.getDateTime(0) + "："+log+"文件夹路径不存在：" + CsvPath+"！<br/>未上传文件！<br/><br/>";
		} else {
			File[] t = f.listFiles();
			System.out.println(DateControl.getDateTime(0)+"共需要上传【"+t.length+"】个文件！");
			Message = DateControl.getDateTime(0)+"共需要上传【"+t.length+"】个文件！<br /><br/>";
			SuccMsg = "已成功上传文件【";
			FailMsg = "以下为上传失败的文件：<br/>";
			
			int SucNum = 0;
			//建立FTP连接
			FTPClient ftp = getConnection(FtpAddress, Integer.parseInt(FtpPort), FtpUser, FtpPass, f.getName());
			for (int i = 0; i < t.length; i++) {
				// 判断文件列表中的对象是否为文件夹对象，如果是则执行tree递归，直到把此文件夹中所有文件输出为止
				if (t[i].isDirectory()) {
					tree(t[i],log);
				} else {
					boolean flag = upLoadFile(ftp, t[i].getName(), CsvRootPath + "/" + f.getName() + "/"+ t[i].getName(),0);
					if (!flag) {
						System.out.println(DateControl.getDateTime(0)+ "："+log+"文件上传失败：" + t[i].getName());
						FailMsg += t[i].getName()+"<br />";
					}else{
						SucNum++;
					}
				}
			}
			SuccMsg += SucNum+"】个！<br/>";
			//关闭连接
			disconnectFtp(ftp);
		}
		
		//邮件发送上传失败文件名称
		List<String> emailTo = emailTo();
		SendMail.getInstance().sendMail("IEMS FTP文件上传  "+DateControl.getFormatDate(DateControl.getDateTime(0), 3)+" 上传失败文件报告", Message+SuccMsg+FailMsg+"<br/>", emailTo);	
	}
	/**
	 * 获取邮件发送人员列表
	 * @return
	 */
	public static List<String> emailTo(){
		String FTPEmail = "";
		try {
			FTPEmail = DynamicReadConfig.getConfigProperty("config.properties", "FTPEmail");
		} catch (ConfigurationException e) {
			e.printStackTrace();
		}
		return (List<String>)Arrays.asList(FTPEmail.split(";"));
	}
	
	//将延迟数据上传至FTP服务器
	public void treeBufferData(Map<String,List<String>> datas){
		Set<String> times = datas.keySet();
		
		
		//建立FTP连接
//		FTPClient ftp = getConnection(FtpAddress, Integer.parseInt(FtpPort), FtpUser, FtpPass, DateControl.getFormatDate(DateControl.getDateTime(1),4)+"延迟数据补充");
		FTPClient ftp = getConnection(FtpAddress, Integer.parseInt(FtpPort), FtpUser, FtpPass, null);
		
		String Message = "";
		String SuccNum = "";
		String SuccMsg = "";
		String FailMsg = "";
		String NotExist = "";
		if(datas == null || datas.size()<=0){
			Message = "没有需要上传的延迟文件！<br/><br/>";
		}else{
			for(String key:times){
				String pathname = DateControl.getFormatDate(key+" 00:00:00",4);
				
				//更改目录
				try {
					ftp.changeToParentDirectory();
					ftp.makeDirectory(pathname);
					ftp.changeWorkingDirectory(pathname);
				} catch (Exception e) {
					e.printStackTrace();
				}
				
				List<String> file = datas.get(key);
				if(file != null && file.size()>0){
					System.out.println(DateControl.getDateTime(0)+" 共需要上传【"+file.size()+"】个延迟文件，文件夹名称为【"+pathname+"】！");
					Message += DateControl.getDateTime(0)+" 共需要上传【"+file.size()+"】个延迟文件，文件夹名称为【"+pathname+"】！<br />";
					SuccNum = "·已成功上传文件【";
					SuccMsg = "·以下为上传成功的文件：<br/>";
					FailMsg = "·以下为上传失败的文件：<br/><span style='color:red'>";
					NotExist = "·以下文件不存在（应该是未生成csv文件）：<br /><span style='color:red'>";
					int SN = 0;
					for (int i = 0; i < file.size(); i++) {
						File f = new File(CsvRootPath + "/" + pathname + "/"+ file.get(i));
						if(f.exists()){
							boolean flag = upLoadFile(ftp, file.get(i), CsvRootPath + "/" + pathname + "/"+ file.get(i),-2);
							if (!flag) {
								System.out.println(DateControl.getDateTime(0)+ "：延迟文件上传失败：" + file.get(i));
								FailMsg += file.get(i)+"<br />";
							}else{
								SuccMsg += file.get(i)+"、";
								SN++;
							}
						}else{
							NotExist += file.get(i)+"<br />";
						}
					}
					SuccNum += SN+"】个！<br/>";
					SuccMsg += "<br />";
					FailMsg += "</span><br />";
					NotExist += "</span>";
					Message +=SuccNum+SuccMsg+FailMsg+NotExist+"<br/><br/>";
				}
			}
		}
		//关闭连接
		disconnectFtp(ftp);
		
		//邮件发送上传失败文件名称
		List<String> emailTo = emailTo();
		SendMail.getInstance().sendMail("IEMS FTP文件上传  "+DateControl.getFormatDate(DateControl.getDateTime(0), 3)+" 上传失败文件报告", Message+"<br/>", emailTo);	
	}

	/**
	 * 上传文件（上传失败后重新上传，最多上传3次）
	 * @param filename	上传到FTP服务器上的文件名
	 * @param orginfilename	 输入流文件名
	 * @return
	 */
	public boolean upLoadFile(FTPClient ftp,String filename,String orginfilename,int times){
		boolean flag=upLoad(ftp,filename,orginfilename,times);
		if(!flag && times<3){	//文件上传失败后重新上传（最多上传3次）
			try {
				Thread.sleep(5000);
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			System.out.println(DateControl.getDateTime(0)+ "：文件上传失败，现重新上传，文件名为：" + orginfilename);
			flag=upLoadFile(ftp,filename,orginfilename,++times);
		}
		return flag;
	}
	
	public boolean upLoad(FTPClient ftp,String filename,String orginfilename,int times){
		boolean flag=false;
		FileInputStream in = null;
		try {
			in = new FileInputStream(new File(orginfilename));
			flag = ftp.storeFile(filename, in);
			if(times>2){
				System.out.println("FTP data Conntion:	PassiveHost:"+ftp.getPassiveHost()+";PassivePort:"+ftp.getPassivePort());
			}
			in.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		return flag;
	}
	
	
	
	/**
	 * 创建连接
	 * @param url	FTP服务器hostname
	 * @param port	FTP服务器端口
	 * @param username	FTP登录账号
	 * @param password	FTP登录密码
	 * @param path	FTP服务器保存目录
	 * @return
	 */
	public FTPClient getConnection(String url,int port,String username,String password,String path){
		FTPClient ftp = new FTPClient();
		ftp.setControlEncoding("UTF-8");
		try {
			int reply;
			ftp.connect(url, port);// 连接FTP服务器
			// 如果采用默认端口，可以使用ftp.connect(url)的方式直接连接FTP服务器
			boolean flag = ftp.login(username, password);// 登录
			if(flag){
				System.out.println(DateControl.getDateTime(0)+"FTP Server Connection Successfully!");
			}else{
				System.out.println(DateControl.getDateTime(0)+"FTP Server Connection Failure!");
			}
			reply = ftp.getReplyCode();
			if (!FTPReply.isPositiveCompletion(reply)) {
				ftp.disconnect();
				System.out.println(DateControl.getDateTime(0)+"FTP Server Connection refused!");
			}
			
			ftp.enterLocalPassiveMode();
			ftp.setFileType(FTPClient.BINARY_FILE_TYPE);
			ftp.makeDirectory(path);
			ftp.changeWorkingDirectory(path);
			
		} catch (IOException e) {
			e.printStackTrace();
		} 
		return ftp;
	}
	
	/**
	 * 关闭连接
	 */
	public void disconnectFtp(FTPClient ftp) {
		if(ftp != null & ftp.isConnected()) {
			try {
				if(ftp.logout()) {
					System.out.println(DateControl.getDateTime(0)+"FTP logouted Successfully!");
				} else {
					System.out.println(DateControl.getDateTime(0)+"FTP logouted failed!");
				}
			} catch(Exception e) {
				System.out.println(DateControl.getDateTime(0)+"FTP logouted failed!");
				e.printStackTrace();
			}
			try {
				System.out.println(DateControl.getDateTime(0)+"disconnecting ftp ...");
				ftp.disconnect();
				System.out.println(DateControl.getDateTime(0)+"disconnected ftp Successfully!");
			} catch (IOException e) {
				System.out.println(DateControl.getDateTime(0)+"FTP disconnect failed!");
				e.printStackTrace();
			}
		}
	}

	public FileToFTPDAO getFileToFTPDAO() {
		return fileToFTPDAO;
	}

	public void setFileToFTPDAO(FileToFTPDAO fileToFTPDAO) {
		this.fileToFTPDAO = fileToFTPDAO;
	}

	public ParamConSaveAsFileService getParamFileService() {
		return paramFileService;
	}

	public void setParamFileService(ParamConSaveAsFileService paramFileService) {
		this.paramFileService = paramFileService;
	}
}
